iT邦幫忙

2021 iThome 鐵人賽

DAY 1
1

Day3

軟體架構

這邊卡比要介紹一個名詞,
Software Architecture 軟體架構

軟體架構 旨在如何更好的處理各個程式碼段落之間的溝通,
雖然並不會讓你的程式碼增加什麼新的功能,但能讓撰寫程式碼變得更容易判讀,

但如果做完之後反而變累贅或是更難懂的時候,重新思考一下,
Don't overengineer your code

GameLoop

如果要論遊戲程式設計最關鍵的部分,那一定是 GameLoop

Loop 的概念在現代開發時常出現,像是 REPL (Read-Eval-Print Loop)Event Loop ...etc.
同樣的概念在遊戲程式中,一樣存在一個 Loop
並會以下面的方式,重複的執行動作,直到使用者主動關閉程式。

示意用

while (true) {
  processesInput();
  update();
  render();
}

根據平台與工具的不同,
實作方式可能會有差異,但主要的思考方向不變,
像是在 Web 端, JavaScript 是無法直接對底層直接做操作的,
必須透過 requestAnimationFrame 等 API 來實現 GameLoop

實際上,卡比在前一章節就已經實作 GameLoop 了,
不過接下來,卡比會做一些調整。

介面

隨著程式的功能越來越複雜,如果將所有的邏輯,都寫在一個函式的話,
最後程式碼會變的難以理解跟維護,
所以卡比會開始整理這些邏輯跟功能到對應的物件進行封裝。

但是,不同的物件會有不同的實作內容,我們需要定義一個共同的 interface
GameLoop 不需要了解是什麼物件,但是知道實作 interface 一定會有其定義的 method
他只需要去執行那個 method 即可。

卡比接下來示範如何用 interface 定義 update 以及 render,來規範架構。

實作

首先建立一個新的檔案 src/types.ts

-- src/types.ts

import { Application } from "pixi.js";

export interface GameObject {
  update(delta: number): void;
  render(stage: Application): void;
}

然後,在 src/characters/Crab.ts
卡比將實作 GameObject 介面,並將他回傳出去。

-- src/characters/Crab.ts

import { Graphics } from "pixi.js";
import { GameObject } from "../types";

const image = [
  [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
  [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
  [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
  [0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0],
  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1],
  [1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1],
  [0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0],
];

const image2 = [
  [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
  [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1],
  [1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1],
  [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1],
  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
  [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
  [0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0],
];

export default function Crab(): GameObject {
  let current = 0;
  const images = [image, image2];

  let timePass = 0;

  return {
    update(delta) {
      timePass += delta;

      if (timePass > 1000) {
        current += 1;
        timePass = 0;
      }
    },

    render(app) {
      const graphics = new Graphics();

      const image = images[current % images.length];

      for (let y = 0; y < image.length; y++) {
        for (let x = 0; x < image[y].length; x++) {
          if (image[y][x] === 0) continue;

          graphics.beginFill(0xffffff);

          graphics.drawRect(x, y, 1, 1);

          graphics.endFill();
        }
      }

      app.stage.addChild(graphics);
    },
  };
}

最後在 src/main.ts

-- src/main.ts

const app = new Application({
  width: 20,
  height: 20,
  resolution: 10,
});

document.querySelector("#app")?.append(app.view);

const instance = Crab();

app.ticker.add(() => {
  app.stage.removeChildren();

  instance.update(app.ticker.deltaMS);

  instance.render(app);
});

接著確認有沒有出現錯誤,或是任何非預期行為,
如果沒有那重構就成功了。

小考題

  1. 請幫 CrabLaserCannonOctopusSquid 也進行重構。

  2. 請在場上同時顯示 CrabLaserCannonOctopusSquid

關於兔兔們:


上一篇
[Day2] Vite 出小蜜蜂~動畫 Animation!
下一篇
[Day4] Vite 出小蜜蜂~ Input Control 操作系統!
系列文
Vite 出小蜜蜂~和卡比一起玩網頁遊戲開發!19
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
bizpro
iT邦大師 1 級 ‧ 2022-09-23 09:54:58

軟體架構 旨在如何更好的處理各個程式碼段落之間的溝通,雖然並不會讓你的程式碼增加什麼新的功能,但能讓撰寫程式碼變得更容易判讀,但如果做完之後反而變累贅或是更難懂的時候,重新思考一下,Don't overengineer your code。

軟體架構是愛麗絲跌進的兔子洞, 敏捷的兔子自能來去自如, 如果變累贅或是更難懂, 那就是做錯了. 可能紅蘿蔔少了.

https://forgeahead.io/blog/down-the-rabbit-hole-software-architecture-and-technical-debt/

我要留言

立即登入留言